package model;

import java.awt.Color;
import java.awt.Dimension;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import javax.swing.JOptionPane;
import model.Length.Orientation;
import model.exception.SVGException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
import view.AppFrame;
import apps.AppReg;

public class SVG {

    private static SVG singletonInstance = new SVG(); // create a singleton
    // instance of itself

    private int width;
    private int height;
    private String filename;
    private String title = null;

    private HashMap<Integer, Shape> shapes = new HashMap<Integer, Shape>();

    private SVG() {
    }

    public float getWidth() {
	return width;
    }

    public float getHeight() {
	return height;
    }

    public String getFilename() {
	return filename;
    }

    public void LoadFile(String file) throws SVGException {

	try {

	    // Read document, returns a Document object
	    File f = new File(file);
	    Document doc = XmlUtil.read(f);

	    shapes.clear(); // Clear shapes

	    // Grab filename and store into class variable
	    this.filename = f.getName();

	    // Get document element / root node
	    Element root = doc.getDocumentElement();

	    if (root.getNodeName() != "svg")
		throw new SVGException("Root node not called <svg>");

	    // Check if it has width or height
	    if (!root.hasAttribute("width") || !root.hasAttribute("height"))
		throw new SVGException(
			"SVG file does not have a width or height or neither");

	    // Get frame dimensions
	    Dimension frameDim = AppReg.getFrame().getSize();

	    // Grab the width and height for the SVG and handle if its a percent
	    Length lenWidth = new Length(root.getAttribute("width"));
	    if (lenWidth.getUnits() == "%")
		this.width = 
		    (int) ((lenWidth.getNumber() / 100) * frameDim.width);
	    else
		this.width = lenWidth.getInPixels();

	    Length lenHeight = new Length(root.getAttribute("height"));
	    if (lenWidth.getUnits() == "%")
		this.height = 
		    (int) ((lenHeight.getNumber() / 100) * frameDim.height);
	    else
		this.height = lenHeight.getInPixels();

	    // Give to length class
	    Length.lengthX = this.width;
	    Length.lengthY = this.height;

	    iterNode(root);

	} catch (SAXException e) {
	    JOptionPane.showMessageDialog(AppReg.getFrame(),
		    "Invalid SVG/XML File", "SAX Exception",
		    JOptionPane.ERROR_MESSAGE);

	} catch (IOException e) {
	    JOptionPane.showMessageDialog(AppReg.getFrame(), "File not found",
		    "IO Exception", JOptionPane.ERROR_MESSAGE);
	}

	AppFrame.getSingletonInstance().repaint();
	AppFrame.getSingletonInstance().getStatusBar().refresh();

    }

    public int numberOfShapes() {
	return this.shapes.size();
    }

    public Shape addShape(Shape shape) {

	this.shapes.put((this.numberOfShapes() + 1), shape);
	return shape;
    }

    public HashMap<Integer, Shape> getShapes() {
	return shapes;
    }

    // singleton instance
    public static SVG getSingletonInstance() {
	return singletonInstance;
    }

    public String getTitle() {
	return title;
    }

    public void iterNode(Node node) {

	// Child nodes
	for (Node child = node.getFirstChild(); child != null; child = child
		.getNextSibling()) {

	    // If its a element node and not just a white space, apparently
	    // XML detects this crap
	    if (child.getNodeType() == Node.ELEMENT_NODE) {
		Element childElem = (Element) child;

		// Stroke
		int stroke = 0; // Default 0
		if (childElem.hasAttribute("stroke-width"))
		 // Could still be none (int safe)
		    if (childElem.getAttribute("stroke-width") != "none")
			stroke = new Length(
				childElem.getAttribute("stroke-width"))
				.getInPixels();

		// Stroke Color
		Color stroke_color = Color.BLACK; // Default black
		if (childElem.hasAttribute("stroke"))
		    stroke_color = SVGColors.parseColor(childElem
			    .getAttribute("stroke"));

		// Fill
		Color fill = null; // now def to null
		// white
		if (childElem.hasAttribute("fill"))
		    fill = SVGColors.parseColor(childElem.getAttribute("fill"));

		// Get the element type
		// A switch statement would be nice here but Java switches
		// only handle ints
		if (childElem.getNodeName() == "rect") {

		    // X
		    int x = 0;
		    if (childElem.hasAttribute("x"))
			x = new Length(childElem.getAttribute("x"),
				Orientation.X).getInPixels();

		    // Y
		    int y = 0;
		    if (childElem.hasAttribute("y"))
			y = new Length(childElem.getAttribute("y"),
				Orientation.Y).getInPixels();

		    // Width
		    int width = 0;
		    if (childElem.hasAttribute("width"))
			width = new Length(childElem.getAttribute("width"),
				Orientation.X).getInPixels();

		    // Height
		    int height = 0;
		    if (childElem.hasAttribute("height"))
			height = new Length(childElem.getAttribute("height"),
				Orientation.Y).getInPixels();

		    Shape shape = new Rect(x, y, stroke, stroke_color, width,
			    height, fill);
		    addShape(shape);

		} else if (childElem.getNodeName() == "circle") {

		    // CX
		    int cx = 0;
		    if (childElem.hasAttribute("cx"))
			cx = new Length(childElem.getAttribute("cx"),
				Orientation.X).getInPixels();

		    // CY
		    int cy = 0;
		    if (childElem.hasAttribute("cy"))
			cy = new Length(childElem.getAttribute("cy"),
				Orientation.Y).getInPixels();

		    // Radius
		    int r = 0;
		    if (childElem.hasAttribute("r"))
			r = new Length(childElem.getAttribute("r"))
				.getInPixels();

		    Shape shape = new Circle(cx, cy, stroke, stroke_color, r,
			    fill);
		    addShape(shape);

		} else if (childElem.getNodeName() == "line") {

		    // X1
		    int x1 = 0;
		    if (childElem.hasAttribute("x1"))
			x1 = new Length(childElem.getAttribute("x1"),
				Orientation.X).getInPixels();

		    // Y1
		    int y1 = 0;
		    if (childElem.hasAttribute("y1"))
			y1 = new Length(childElem.getAttribute("y1"),
				Orientation.Y).getInPixels();

		    // X2
		    int x2 = 0;
		    if (childElem.hasAttribute("x2"))
			x2 = new Length(childElem.getAttribute("x2"),
				Orientation.X).getInPixels();

		    // Y2
		    int y2 = 0;
		    if (childElem.hasAttribute("y2"))
			y2 = new Length(childElem.getAttribute("y2"),
				Orientation.Y).getInPixels();

		    Shape shape = 
			new Line(x1, y1, x2, y2, stroke, stroke_color);
		    addShape(shape);

		} else if (childElem.getNodeName() == "g") {

		    // Recursive
		    iterNode(childElem);

		}

		else {
		    // Unknown element
		    System.out.println("Unknown element: "
			    + childElem.getNodeName());
		}
	    }
	}
    }
}
